#include "button.h"

enum BTN_STAGE {
    BTN_STAGE_DEFAULT = 0,
    BTN_STAGE_DOWN = 1,
};

#define EVENT_SET_AND_EXEC_CB(btn,evt)                  \
    do                                                  \
    {                                                   \
        btn->_event = evt;                              \
        if(btn->cb)                                     \
            btn->cb((void *)btn);                               \
    } while (0)


button_t* btn;

int32_t button_register(button_t* btn_t) {
    btn = btn_t;
    btn->_status = BTN_STAGE_DEFAULT;
    btn->_scan_cnt = 0;
    btn->_event = BTN_EVENT_PRESS_NONE;
}
button_event_t button_event_read(button_t* btn) {
    return btn->_event;
}

static uint8_t button_process(void)
{
    button_t* target = btn;
    if (target->_status > BTN_STAGE_DEFAULT) {
        target->_scan_cnt++;
        if (target->_scan_cnt >= (1 << sizeof(target->_scan_cnt) * 8) - 1) {
            target->_scan_cnt = target->click_hold_start_tick;
        }
    }
    switch (target->_status)
    {
        case BTN_STAGE_DEFAULT:
            if (target->usr_button_read(target)) {
                EVENT_SET_AND_EXEC_CB(target, BTN_EVENT_PRESS_DOWN);
                target->_scan_cnt = 0;
                target->_status = BTN_STAGE_DOWN;
            }
            else {
                target->_event = BTN_EVENT_PRESS_NONE;
            }
            break;
        case BTN_STAGE_DOWN:
            if (target->usr_button_read(target)) {
                if (target->_scan_cnt >= target->click_hold_start_tick) {
                    if (target->_event != BTN_EVENT_PRESS_DOWN) {
                        EVENT_SET_AND_EXEC_CB(target, BTN_EVENT_PRESS_DOWN);
                    }
                }
            }
            else {
                if (target->_scan_cnt >= target->click_hold_start_tick) {
                    EVENT_SET_AND_EXEC_CB(target, BTN_EVENT_PRESS_CLICK);
                    target->_status = BTN_STAGE_DEFAULT;
                }
            }
            break;

    }
    return 1;
}
uint8_t button_scan(void) {
    btn->usr_button_read(btn);
    return button_process();
}